package com.powernode.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powernode.constant.BusinessEnum;
import com.powernode.constant.QueueConstants;
import com.powernode.domain.*;
import com.powernode.ex.handler.BusinessException;
import com.powernode.feign.OrderBasketFeign;
import com.powernode.feign.OrderMemberFeign;
import com.powernode.feign.OrderProductFeign;
import com.powernode.mapper.OrderItemMapper;
import com.powernode.mapper.OrderMapper;
import com.powernode.model.*;
import com.powernode.ov.OrderStatusCount;
import com.powernode.service.OrderItemService;
import com.powernode.service.OrderService;
import com.powernode.util.AuthUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 贺
 * @description 针对表【order(订单表)】的数据库操作Service实现
 * @createDate 2024-07-20 09:17:52
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
        implements OrderService {

    @Resource
    private OrderMapper orderMapper;
    @Resource
    private OrderItemMapper orderItemMapper;
    @Resource
    private OrderMemberFeign orderMemberFeign;
    @Resource
    private OrderProductFeign orderProductFeign;
    @Resource
    private OrderBasketFeign orderBasketFeign;
    @Resource
    private Snowflake snowflake;
    @Resource
    private OrderItemService orderItemService;
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 多条件分页查询订单列表
     *
     * @param page
     * @param orderNumber
     * @param status
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public Page<Order> queryOrderPage(Page<Order> page, String orderNumber, Integer status, Date startTime, Date endTime) {

        // 多条件分页查询订单列表
        page = orderMapper.selectPage(page, new LambdaQueryWrapper<Order>()
                .eq(ObjectUtil.isNotNull(status), Order::getStatus, status)
                .eq(StringUtils.hasText(orderNumber), Order::getOrderNumber, orderNumber)
                .between(ObjectUtil.isAllNotEmpty(startTime, endTime), Order::getCreateTime, startTime, endTime)
                .orderByDesc(Order::getCreateTime));

        // 从订单分页对象中获取订单集合
        List<Order> orderList = page.getRecords();
        // 判断订单集合是否为空
        if (CollectionUtil.isEmpty(orderList) || orderList.size() == 0) {
            return page;
        }
        // 从订单集合中获取订单编号集合，订单编号orderNumber是订单的唯一标识
        List<String> orderNumberList = orderList.stream().map(Order::getOrderNumber).collect(Collectors.toList());
        // 根据订单编号查询订单包含的所有订单条目对象集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .in(OrderItem::getOrderNumber, orderNumberList)
        );

        // 遍历订单集合
        orderList.forEach(order -> {
            // 获取当前订单的订单编号
            String orderNumber1 = order.getOrderNumber();
            // 从订单条目对象集合中过滤到当前订单包含的订单条目对象集合
            List<OrderItem> itemList = orderItemList.stream().filter(orderItem -> orderItem.getOrderNumber().equals(orderNumber1)).collect(Collectors.toList());
            // 设置当前订单的订单条目集合
            order.setOrderItems(itemList);
        });

        return page;
    }

    /**
     * 根据订单编号查询订单详情
     *
     * @param orderNumber
     * @return
     */
    @Override
    public Order queryOrderInfo(String orderNumber) {
        // 根据订单编号查询订单对象
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>()
                .eq(Order::getOrderNumber, orderNumber)
        );

        // 根据订单编号查询订单条目对象集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, orderNumber)
        );
        // 设置订单的订单条目集合
        if (CollectionUtil.isNotEmpty(orderItemList) && orderItemList.size() > 0) {
            order.setOrderItems(orderItemList);
        }

        // 从订单对象中获取订单收货地址ID
        Long addrOrderId = order.getAddrOrderId();
        // 远程调用：根据订单收货地址ID查询订单收货地址对象
        Result<MemberAddr> result = orderMemberFeign.getMemberAddrById(addrOrderId);
        // 判断远程调用结果
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(result.getCode())) {
            throw new BusinessException("远程调用会员服务中根据地址ID查询会员收货地址的接口失败");
        }
        order.setUserAddrOrder(result.getData());

        // 远程调用：根据会员openId查询会员昵称
        Result<String> result1 = orderMemberFeign.getNickNameByOpenId(order.getOpenId());
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(result1.getCode())) {
            throw new BusinessException("远程调用会员服务中根据会员openId查询会员昵称的接口失败");
        }
        order.setNickName(result1.getData());

        return order;
    }

    /**
     * 查询会员订单各个状态的数量
     *
     * @return
     */
    @Override
    public OrderStatusCount queryMemberOrderStatusCount() {
        // 获取会员的openId
        String openId = AuthUtils.getMemberOpenId();
        // 根据会员openId查询订单各个状态的数量
        // 待支付数量
        Long unpay = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getOpenId, openId)
                .eq(Order::getStatus, 1));
        // 待发货数量
        Long payed = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getOpenId, openId)
                .eq(Order::getStatus, 2));
        // 待收货数量
        Long consignment = orderMapper.selectCount(new LambdaQueryWrapper<Order>()
                .eq(Order::getOpenId, openId)
                .eq(Order::getStatus, 3));

        return OrderStatusCount.builder()
                .unPay(unpay).payed(payed).consignment(consignment)
                .build();
    }

    /**
     * 分页查询会员订单列表
     *
     * @param current
     * @param size
     * @param status
     * @return
     */
    @Override
    public Page<Order> queryMemberOrderPage(Long current, Long size, Integer status) {
        // 获取会员openId
        String openId = AuthUtils.getMemberOpenId();
        // 分页查询会员订单列表
        Page<Order> page = new Page<>(current, size);
        page = orderMapper.selectPage(page, new LambdaQueryWrapper<Order>()
                .eq(Order::getOpenId, openId)
                .eq(0 != status, Order::getStatus, status)
                .eq(Order::getDeleteStatus, 0)
                .orderByDesc(Order::getCreateTime)
        );
        // 从订单分页对象中获取订单集合
        List<Order> orderList = page.getRecords();
        // 判断订单集合是否为空
        if (CollectionUtil.isEmpty(orderList) || orderList.size() == 0) {
            return page;
        }
        // 从订单集合中获取订单编号集合，订单编号orderNumber是订单的唯一标识
        List<String> orderNumberList = orderList.stream().map(Order::getOrderNumber).collect(Collectors.toList());
        // 根据订单编号查询订单包含的所有订单条目对象集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .in(OrderItem::getOrderNumber, orderNumberList)
        );
        // 遍历订单集合，设置订单的订单条目集合
        orderList.forEach(order -> {
            // 从所有的订单条目对象集合中过滤出当前订单包含的订单条目对象集合
            List<OrderItem> itemList = orderItemList.stream().filter(orderItem -> orderItem.getOrderNumber().equals(order.getOrderNumber())).collect(Collectors.toList());
            order.setOrderItemDtos(itemList);
        });
        return page;
    }

    /**
     * 根据订单编号查询订单详情
     *
     * @param orderNumber
     * @return
     */
    @Override
    public Order queryMemberOrderDetail(String orderNumber) {
        // 查询订单基本信息
        Order order = orderMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderNumber));

        // 判断订单是否存在
        if (ObjectUtil.isNull(order)) {
            throw new BusinessException("订单编号有误");
        }

        // 远程调用：查询订单收货地址对象
        Result<MemberAddr> memberAddrResult = orderMemberFeign.getMemberAddrById(order.getAddrOrderId());
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(memberAddrResult.getCode())) {
            throw new BusinessException("远程调用会员服务中根据地址ID查询会员收货地址的接口失败");
        }
        // 获取订单收货地址对象
        MemberAddr memberAddr = memberAddrResult.getData();
        order.setUserAddrDto(memberAddr);

        // 根据订单编号查询订单商品条目对象集合
        List<OrderItem> orderItemList = orderItemMapper.selectList(new LambdaQueryWrapper<OrderItem>()
                .eq(OrderItem::getOrderNumber, orderNumber)
        );
        // 判断订单商品条目对象集合是否为空
        if (CollectionUtil.isNotEmpty(orderItemList) && orderItemList.size() > 0) {
            order.setOrderItemDtos(orderItemList);
        }

        return order;
    }

    /**
     * 会员确认收货
     *
     * @param orderNumber
     * @return
     */
    @Override
    public Boolean receiptMemberOrder(String orderNumber) {
        // 创建订单对象
        Order order = new Order();
        order.setUpdateTime(new Date());
        order.setFinallyTime(new Date());
        order.setStatus(5);
        return orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderNumber)) > 0;
    }

    /**
     * 会员删除已完成订单
     *
     * @param orderNumber
     * @return
     */
    @Override
    public Boolean removeMemberOrder(String orderNumber) {
        Order order = new Order();
        order.setUpdateTime(new Date());
        order.setDeleteStatus(1);
        return orderMapper.update(order, new LambdaQueryWrapper<Order>().eq(Order::getOrderNumber, orderNumber)) > 0;
    }

    /**
     * 查询会员确认订单页面数据
     *
     * @param orderConfirmParam
     * @return
     */
    @Override
    public OrderVo queryMemberOrderConfirmVo(OrderConfirmParam orderConfirmParam) {
        // 创建订单确认页面对象
        OrderVo orderVo = new OrderVo();

        // 获取会员openId
        String openId = AuthUtils.getMemberOpenId();

        // 远程调用：根据会员openId查询会员默认收货地址
        Result<MemberAddr> memberDefaultAddrResult = orderMemberFeign.getMemberDefaultAddrByOpenId(openId);
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(memberDefaultAddrResult.getCode())) {
            throw new BusinessException("远程调用会员服务中根据会员openId查询会员默认收货地址的接口失败");
        }
        // 获取会员的默认收货地址
        MemberAddr memberDefaultAddr = memberDefaultAddrResult.getData();
        orderVo.setMemberAddr(memberDefaultAddr);

        // 从订单确认页面参数对象中获取购物车记录id集合
        List<Long> basketIds = orderConfirmParam.getBasketIds();
        // 根据购物车记录id集合是否为空，判断订单确认页面请求来自于购物车页面还是商品详情页面
        if (CollectionUtil.isEmpty(basketIds) || basketIds.size() == 0) {
            // 请求来自于商品详情页面
            prod2OrderConfirm(orderConfirmParam.getOrderItem(), orderVo);
        } else {
            // 请求来自于购物车页面
            // 设置订单确认页面对象的请求来源属性值为1，表示请求来自购物车页面（默认值为0，表示请求来自商品详情页面）
            orderVo.setSource(1);
            cart2OrderConfirm(basketIds, orderVo);
        }

        return orderVo;
    }

    /**
     * 订单确认页面请求来自于购物车页面
     * 根据购物车记录id集合可以获取购物车记录对象集合
     * 根据购物车记录对象可以获取购物车商品数量
     * 根据购物车记录对象可以获取商品skuId，根据商品skuId查询商品sku对象进而获取商品价格
     * 根据购物车商品数量和商品价格可以计算单个购物车商品的总金额，进而累计订单总金额
     * @param basketIds
     * @param orderVo
     */
    private void cart2OrderConfirm(List<Long> basketIds, OrderVo orderVo) {
        // 判断购物车记录id集合是否为空
        if (CollectionUtil.isEmpty(basketIds) || basketIds.size() == 0) {
            return;
        }
        // 远程调用：根据购物车记录id集合查询购物车记录对象集合
        Result<List<Basket>> basketLisResult = orderBasketFeign.getBasketListByIds(basketIds);
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(basketLisResult.getCode())) {
            throw new BusinessException("远程调用购物车服务中根据购物车记录id集合查询购物车记录的接口失败");
        }
        // 获取购物车记录对象集合
        List<Basket> basketList = basketLisResult.getData();
        // 从购物车记录对象集合中获取商品skuId集合
        List<Long> skuIdList = basketList.stream().map(Basket::getSkuId).collect(Collectors.toList());
        // 远程调用：根据商品skuId集合查询商品sku对象集合
        Result<List<Sku>> skuListResult =  orderProductFeign.getSkuListByIds(skuIdList);
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(skuListResult.getCode())) {
            throw new BusinessException("远程调用商品服务中根据商品skuId集合查询商品sku的接口失败");
        }
        // 获取商品sku对象集合
        List<Sku> skuList = skuListResult.getData();

        // 创建订单店铺对象集合
        List<ShopOrder> shopOrderList = new ArrayList<>();

        // 将购物车记录对象集合按照商品店铺id分组
        Map<Long, List<Basket>> allShopOrderMap = basketList.stream().collect(Collectors.groupingBy(Basket::getShopId));

        // 创建所有单个商品总金额集合
        List<BigDecimal> oneSkuTotalAmounts = new ArrayList<>();
        // 创建所有单个商品购买数量集合
        List<Integer> oneSkuCounts = new ArrayList<>();

        // 遍历allShopOrderMap
        allShopOrderMap.forEach((shopId, baskets) -> {
            // 创建订单店铺对象
            ShopOrder shopOrder = new ShopOrder();
            // 创建订单商品条目对象集合
            List<OrderItem> orderItemList = new ArrayList<>();
            // 遍历当前订单店铺对象中的购物车记录对象集合baskets
            baskets.forEach(basket -> {
                // 获取购买商品数量
                Integer prodCount = basket.getProdCount();
                oneSkuCounts.add(prodCount);

                // 获取商品sku对象
                Sku sku = skuList.stream().filter(s -> s.getSkuId().equals(basket.getSkuId())).findFirst().get();
                // 获取商品价格
                BigDecimal price = sku.getPrice();

                // 创建订单商品条目对象
                OrderItem orderItem = new OrderItem();
                // 补充订单商品条目对象属性
                /*orderItem.setShopId();
                orderItem.setProdId();
                orderItem.setSkuId();
                orderItem.setProdCount();*/
                // 上面的4个属性可以直接使用BeanUtils.copyProperties()方法进行赋值
                BeanUtils.copyProperties(basket, orderItem);
                /*orderItem.setProdName();
                orderItem.setSkuName();
                orderItem.setPic();
                orderItem.setPrice();*/
                // 上面的4个属性可以直接使用BeanUtils.copyProperties()方法进行赋值
                BeanUtils.copyProperties(sku, orderItem);

                // 计算当前商品的总金额
                BigDecimal oneSkuTotalAmount = price.multiply(new BigDecimal(prodCount));
                oneSkuTotalAmounts.add(oneSkuTotalAmount);

                orderItem.setProductTotalAmount(oneSkuTotalAmount);
                orderItem.setCreateTime(new Date());
                orderItem.setCommSts(0);

                orderItemList.add(orderItem);
            });
            shopOrder.setShopId(shopId);
            shopOrder.setShopOrderItems(orderItemList);
            shopOrderList.add(shopOrder);
        });

        // 计算所有购买商品的数量总和
        Integer allSkuCount = oneSkuCounts.stream().reduce(Integer::sum).get();

        // 计算所有购买商品的总金额之和
        BigDecimal allSkuTotalAmount = oneSkuTotalAmounts.stream().reduce(BigDecimal::add).get();

        // 补充订单确认页面对象属性
        orderVo.setShopCartOrders(shopOrderList);
        orderVo.setTotalCount(allSkuCount);
        orderVo.setTotal(allSkuTotalAmount);
        orderVo.setActualTotal(allSkuTotalAmount);
        // 约定运费规则：满99元免运费，少于99元，运费为6元
        if (allSkuTotalAmount.compareTo(new BigDecimal(99)) < 0) {
            orderVo.setTransfee(new BigDecimal(6));
            orderVo.setActualTotal(allSkuTotalAmount.add(new BigDecimal(6)));
        }
    }

    /**
     * 订单确认页面请求来自于商品详情页面
     * @param orderItem
     * @param orderVo
     */
    private void prod2OrderConfirm(OrderItem orderItem, OrderVo orderVo) {

        // 获取商品skuId
        Long skuId = orderItem.getSkuId();
        // 根据商品skuId查询商品sku对象
        Result<List<Sku>> skuListResult =  orderProductFeign.getSkuListByIds(Collections.singletonList(skuId));
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(skuListResult.getCode())) {
            throw new BusinessException("远程调用商品服务中根据商品skuId查询商品sku的接口失败");
        }
        // 获取商品sku对象
        List<Sku> skuList = skuListResult.getData();
        Sku sku = skuList.get(0);

        // 获取商品购买数量
        Integer prodCount = orderItem.getProdCount();
        // 获取商品价格
        BigDecimal price = sku.getPrice();

        // 计算单个商品总金额
        BigDecimal oneSkuTotalAmount = price.multiply(new BigDecimal(prodCount));

        // 获取欲购商品的店铺id
        Long shopId = orderItem.getShopId();

        // 创建订单店铺对象集合
        List<ShopOrder> shopOrderList = new ArrayList<>();
        // 创建订单店铺对象
        ShopOrder shopOrder = new ShopOrder();
        // 创建订单商品条目对象集合
        List<OrderItem> orderItemList = new ArrayList<>();

        // 补充订单商品条目对象属性
        orderItem.setProductTotalAmount(oneSkuTotalAmount);
        orderItem.setCreateTime(new Date());
        orderItem.setCommSts(0);
        /*orderItem.setProdName();
        orderItem.setSkuName();
        orderItem.setPic();
        orderItem.setPrice();*/
        // 属性拷贝
        BeanUtils.copyProperties(sku, orderItem);

        orderItemList.add(orderItem);
        // 补充订单店铺对象属性
        shopOrder.setShopId(shopId);
        shopOrder.setShopOrderItems(orderItemList);

        shopOrderList.add(shopOrder);

        // 补充订单确认页面对象属性
        orderVo.setShopCartOrders(shopOrderList);
        orderVo.setTotalCount(prodCount);
        orderVo.setTotal(oneSkuTotalAmount);
        orderVo.setActualTotal(oneSkuTotalAmount);
        // 约定运费规则：满99元免运费，少于99元，运费为6元
        if (oneSkuTotalAmount.compareTo(new BigDecimal(99)) < 0) {
            orderVo.setTransfee(new BigDecimal(6));
            orderVo.setActualTotal(oneSkuTotalAmount.add(new BigDecimal(6)));
        }
        // 满99元免运费，默认值为0
        // orderVo.setTransfee();// 默认值0

        // orderVo.setShopReduce();// 默认值0

        // orderVo.setRemark();// 默认值空

    }

    /**
     * 会员提交订单
     * 1. 判断订单请求来源：0商品详情页面，1购物车页面
     *      如果是购物车页面，删除提交订单时购物车中选中的商品条目
     *      想要从购物车记录表basket中删除记录，要么根据主键basket_id，要么根据open_id和sku_id，这些字段可以确定购物车记录的唯一性
     * 2. 修改商品prod和sku的库存，需要返回prod和sku库存的扣减数量
     *      封装sku购买数量对象：SkuChange，包含两个属性：skuId、sku购买数量count
     *      封装prod购买数量对象：ProdChange，包含两个属性：prodId、prod购买数量count
     *      封装商品prod和sku购买刷领对象：ChangeStock，包含两个属性：prod购买数量对象集合，sku购买数量对象集合
     *      上述三个对象，不仅order-service中需要用到，在product-service中也需要，因此创建在common-base工程中
     * 3. 写订单：订单表order，订单商品条目表order_item
     * 4. 解决超时未支付问题：延迟队列、死信队列
     *
     * @param orderVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitOrder(OrderVo orderVo) {
        // 获取会员openId
        String openId = AuthUtils.getMemberOpenId();

        // 1. 判断订单请求来源：0商品详情页面，1购物车页面
        Integer source = orderVo.getSource();
        if (1 == source) {
            // 提交订单的请求来自购物车，删除提交订单时购物车中选中的商品条目
            clearMemberCheckedItemsInBasket(openId, orderVo);
        }

        // 2. 修改商品prod和sku的库存，需要返回prod和sku库存的扣减数量
        ChangeStock changeStock = changeProdAndSkuStock(orderVo);

        // 3. 写订单：订单表order，订单商品条目表order_item
        // 生成全局唯一订单编号orderNumber：雪花算法
        String orderNumber = generateOrderNumber();
        writeOrder(openId, orderNumber, orderVo);

        // 4. 解决超时未支付问题：延迟队列、死信队列
        sendMsg(orderNumber, changeStock);

        return orderNumber;
    }




    /**
     * 会员提交订单：删除提交订单时购物车中选中的商品条目
     * @param openId 会员openId
     * @param orderVo 订单确认页面对象
     */
    private void clearMemberCheckedItemsInBasket(String openId, OrderVo orderVo) {
        // 创建订单中所有商品的skuId集合
        List<Long> allSkuIdList = new ArrayList<>();

        // 获取提交订单时购物车中选中的商品条目的skuId集合
        // 获取订单店铺对象集合
        List<ShopOrder> shopOrderList = orderVo.getShopCartOrders();
        // 遍历订单店铺对象集合
        shopOrderList.forEach(shopOrder -> {
            // 获取当前订单店铺对象的商品条目对象集合
            List<OrderItem> orderItemList = shopOrder.getShopOrderItems();
            // 从商品条目对象集合中获取skuId集合
            List<Long> skuIdList = orderItemList.stream().map(OrderItem::getSkuId).collect(Collectors.toList());
            allSkuIdList.addAll(skuIdList);
        });

        // 根据会员openId和商品skuId集合，批量删除提交订单时选中的购物车记录
        // 准备参数
        Map<String, Object> param = new HashMap<>();
        param.put("openId", openId);
        param.put("skuIdList", allSkuIdList);
        // 远程调用购物车服务，批量删除提交订单时选中的购物车记录
        Result<Boolean> booleanResult = orderBasketFeign.removeBasketByOpenIdAndSkuIds(param);
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(booleanResult.getCode())) {
            throw new BusinessException("远程调用购物车服务中批量删除提交订单时选中的购物车记录的接口失败");
        }
    }


    /**
     * 会员提交订单：记录商品prod和sku的库存数量变化
     * @param orderVo
     * @return
     */
    private ChangeStock changeProdAndSkuStock(OrderVo orderVo) {
        // 创建商品prod购买数量对象集合
        List<ProdChange> prodChangeList = new ArrayList<>();
        // 创建商品sku购买数量对象集合
        List<SkuChange> skuChangeList = new ArrayList<>();

        // 获取订单店铺对象集合
        List<ShopOrder> shopOrderList = orderVo.getShopCartOrders();
        // 遍历订单店铺对象集合
        shopOrderList.forEach(shopOrder -> {
            // 获取当前订单店铺对象的商品条目对象集合
            List<OrderItem> orderItemList = shopOrder.getShopOrderItems();
            // 遍历商品条目对象集合
            orderItemList.forEach(orderItem -> {
                // 获取商品prodId
                Long prodId = orderItem.getProdId();
                // 获取商品skuId
                Long skuId = orderItem.getSkuId();
                // 获取商品购买数量
                // 下订单的时候，设置商品prod和sku的购买数量都是负数，在扣减商品prod和sku库存时直接与字段值相加就是扣减操作；
                // 而订单超时未支付或者会员取消订单时，从ChangeStock对象中获取商品prod和sku的购买数量时设置其为正数，这样恢复商品prod和sku的库存时就可以与扣减库存操作使用同一个SQL语句
                Integer prodCount = orderItem.getProdCount() * -1;

                // 判断当前商品prodId是否在商品prod购买数量对象集合中出现过
                List<ProdChange> oneProdChange = prodChangeList.stream()
                        .filter(prodChange -> prodChange.getProdId().equals(prodId))
                        .collect(Collectors.toList());
                if (CollectionUtil.isEmpty(oneProdChange) || oneProdChange.size() == 0) {
                    // 当前商品prodId没有在商品prod购买数量对象集合中出现过
                    // 创建商品prod购买数量对象
                    ProdChange prodChange = new ProdChange(prodId, prodCount);
                    // 创建商品sku购买数量对象
                    SkuChange skuChange = new SkuChange(skuId, prodCount);

                    prodChangeList.add(prodChange);
                    skuChangeList.add(skuChange);
                } else {
                    // 当前商品prodId在商品prod购买数量对象集合中出现过
                    // 在之前购买的商品prod数量基础上累加当前商品购买数量
                    ProdChange prodChange = oneProdChange.get(0);
                    prodChange.setCount(prodChange.getCount() + prodCount);
                    // 创建商品sku购买数量对象
                    SkuChange skuChange = new SkuChange(skuId, prodCount);

                    skuChangeList.add(skuChange);
                }
            });
        });

        // 创建商品prod和sku购买数量对象
        ChangeStock changeStock = new ChangeStock(prodChangeList, skuChangeList);

        // 远程调用：修改商品prod和sku的库存
        Result<Boolean> booleanResult = orderProductFeign.changeProdAndSkuStock(changeStock);
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(booleanResult.getCode())) {
            throw new BusinessException("远程调用修改商品prod和sku的库存的接口失败");
        }

        if (!booleanResult.getData()) {
            throw new BusinessException("远程调用修改商品prod和sku的库存的接口失败");
        }

        return changeStock;
    }

    /**
     * 使用雪花算法生成全局唯一订单编号
     * @return
     */
    private String generateOrderNumber() {
        return snowflake.nextIdStr();
    }

    /**
     * 会员提交订单：写订单，订单表order和订单商品条目表order_item
     * @param openId
     * @param orderNumber
     * @param orderVo
     */
    private void writeOrder(String openId, String orderNumber, OrderVo orderVo) {
        // 创建订单中所有商品条目对象集合
        List<OrderItem> allOrderItemList = new ArrayList<>();

        // 获取订单店铺对象集合
        List<ShopOrder> shopOrderList = orderVo.getShopCartOrders();
        // 遍历订单店铺对象集合
        shopOrderList.forEach(shopOrder -> {
            // 获取当前订单店铺对象的商品条目对象集合
            List<OrderItem> orderItemList = shopOrder.getShopOrderItems();
            // 遍历商品条目对象集合
            orderItemList.forEach(orderItem -> orderItem.setOrderNumber(orderNumber));
            // 收集订单中所有的商品条目对象
            allOrderItemList.addAll(orderItemList);
        });

        // 批量添加数据到订单商品条目表order_item
        boolean saved = orderItemService.saveBatch(allOrderItemList);

        if (saved) {
            // 添加记录到订单表order
            Order order = new Order();
            order.setOpenId(openId);
            order.setOrderNumber(orderNumber);
            order.setTotalMoney(orderVo.getTotal());
            order.setActualTotal(orderVo.getActualTotal());
            order.setRemarks(orderVo.getRemarks());
            order.setStatus(1);
            order.setFreightAmount(orderVo.getTransfee());
            order.setAddrOrderId(orderVo.getMemberAddr().getAddrId());
            order.setProductNums(orderVo.getTotalCount());
            order.setCreateTime(new Date());
            order.setUpdateTime(new Date());
            order.setIsPayed(0);
            order.setDeleteStatus(0);
            order.setRefundSts(0);
            order.setReduceAmount(orderVo.getShopReduce());
            orderMapper.insert(order);
        }
    }


    /**
     * 会员提交订单：使用延迟队列和死信队列解决订单超时未支付问题
     * @param orderNumber
     * @param changeStock
     */
    private void sendMsg(String orderNumber, ChangeStock changeStock) {
        // 将数据存放到json对象中，并转为json字符串
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("orderNumber", orderNumber);
        jsonObject.put("changeStock", changeStock);

        // 发送消息
        rabbitTemplate.convertAndSend(QueueConstants.ORDER_MS_QUEUE, jsonObject.toJSONString());
    }

    /**
     * 会员提交订单：超时未支付订单数据回滚
     *
     * @param order
     * @param changeStock
     */
    @Override
    public void orderRollback(Order order, ChangeStock changeStock) {
        // 修改订单状态为失败（6），订单关闭类型为超时未支付（1）
        order.setStatus(6);
        order.setUpdateTime(new Date());
        order.setFinallyTime(new Date());
        order.setCloseType(1);
        orderMapper.updateById(order);

        // 回滚商品prod和sku的库存数量
        List<ProdChange> prodChangeList = changeStock.getProdChangeList();
        prodChangeList.forEach(prodChange -> prodChange.setCount(prodChange.getCount() * -1));
        List<SkuChange> skuChangeList = changeStock.getSkuChangeList();
        skuChangeList.forEach(skuChange -> skuChange.setCount(skuChange.getCount() * -1));

        // 远程调用：修改商品prod和sku的库存
        Result<Boolean> booleanResult = orderProductFeign.changeProdAndSkuStock(changeStock);
        // 判断远程调用是否成功
        if (BusinessEnum.OPERATION_FAIL.getCode().equals(booleanResult.getCode())) {
            throw new BusinessException("远程调用产品业务接口，回滚商品prod和sku的库存数量失败");
        }
        if (!booleanResult.getData()) {
            throw new BusinessException("远程调用产品业务接口，回滚商品prod和sku的库存数量失败");
        }
    }
}




